from typing import Tuple

from datetime import datetime, timedelta
from zoneinfo import ZoneInfo


TZ_SHANGHAI = ZoneInfo('Asia/Shanghai')


class UTCAdd8TimeHelper:
    TZ = TZ_SHANGHAI

    @staticmethod
    def now() -> datetime:
        return datetime.now(tz=UTCAdd8TimeHelper.TZ)

    @staticmethod
    def astimezone(dt: datetime) -> datetime:
        """
        转换本时区时间
        """
        # 如果输入的时间没有时区信息，则假设它为北京时间
        if dt.tzinfo is None:
            tz_time = dt.replace(tzinfo=UTCAdd8TimeHelper.TZ)
        else:
            # 如果有时区信息，转换到北京时间
            tz_time = dt.astimezone(UTCAdd8TimeHelper.TZ)

        return tz_time

    @classmethod
    def today_start(cls) -> datetime:
        """
        今天日期开始时间(零点时间)
        """
        return cls.now().replace(hour=0, minute=0, second=0, microsecond=0)

    @staticmethod
    def get_week_range(dt: datetime) -> Tuple[datetime, datetime]:
        """
        给定一个时间，获取该周的起始和结束时间，本周一至下个周一起始时间
        """
        # 如果输入的时间没有时区信息，则假设它为北京时间
        tz_time = UTCAdd8TimeHelper.astimezone(dt)

        # 找到该日期所在周的周一
        start_of_week = tz_time - timedelta(days=tz_time.weekday())
        # 设置时间为当天的 00:00:00
        start_of_week = start_of_week.replace(hour=0, minute=0, second=0, microsecond=0)

        # 该周的周日为周一 + 6 天
        end_of_week = start_of_week + timedelta(days=7)

        return start_of_week, end_of_week

    @staticmethod
    def get_week_range_ts(ts: int) -> Tuple[int, int]:
        """
        给定一个时间戳，获取该周的起始和下个周的起始时间戳
        """
        dt = datetime.fromtimestamp(ts, tz=UTCAdd8TimeHelper.TZ)
        start_of_week, end_of_week = UTCAdd8TimeHelper.get_week_range(dt)
        return int(start_of_week.timestamp()), int(end_of_week.timestamp())

    @staticmethod
    def get_day_range_ts(ts: int) -> Tuple[int, int]:
        """
        给定一个时间戳，获取该日的起始和下一日的开始时间戳
        """
        dt = datetime.fromtimestamp(ts, tz=UTCAdd8TimeHelper.TZ)
        day_start = dt.replace(hour=0, minute=0, second=0, microsecond=0)
        next_day_start = day_start + timedelta(days=1)
        return int(day_start.timestamp()), int(next_day_start.timestamp())
